package net.oschina.app.ui;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.support.v7.app.ActionBar;

import android.os.Bundle;
import android.text.Editable;
import android.text.Html;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.text.style.ImageSpan;
import android.util.SparseArray;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import com.loopj.android.http.AsyncHttpResponseHandler;

import net.oschina.app.AppContext;
import net.oschina.app.R;
import net.oschina.app.api.remote.OSChinaApi;
import net.oschina.app.base.BaseActivity;
import net.oschina.app.bean.Friend;
import net.oschina.app.bean.FriendsList;
import net.oschina.app.ui.empty.EmptyLayout;
import net.oschina.app.util.StringUtils;
import net.oschina.app.util.XmlUtils;
import net.oschina.app.widget.AlphabetBar;

import org.apache.http.Header;
import org.kymjs.kjframe.KJBitmap;

import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;


/**
 *
 * @author Darcy www.darcye.com
 *
 */
public class SelectUserActivity extends BaseActivity {

    private static final String HIGHLIGHT_COLOR = "#cc0000";
    private static final String HIGHLIGHT_REPLACEMENT = String.format("<font color=\"%s\">$1</font>",HIGHLIGHT_COLOR);
    private static final char OTHER_INDEX_CHAR = Character.MAX_VALUE;

    private static final int MSG_DATA_PROCESS = 0x10000;
    private static final int MSG_DATA_PROCESS_SUCCESS = 0x10001;

    private static final int MSG_SEARCH_FRIENDS = 0x20000;
    private static final int MSG_SEARCH_FRIENDS_SUCCESS = 0x20001;

    private static final int MSG_SELECT_USERS_PROCESS = 0x30000;
    private static final int MSG_SELECT_USERS_PROCESS_SUCCESS = 0x30001;

    private static final int MAX_SELECT_USER_COUNT = 10;

    public static final String RESULT_AT_USERS = "at_users";

    private EmptyLayout mEmptyLayout;
    private TextView mTvConfirm;
    private EditText mEtSearch;
    private TextView mTvSelectedUsers;
    private AlphabetBar mAlphaBar;
    private TextView mTvAlphaTip;
    private ListView mLvFriends;
    private FriendListAdapter mLvAdapter;

    private List<ItemModel> mAllMdlFriends;
    private List<ItemModel> mShowMdlFriends;
    private Set<Friend> mSelectedFriends = new LinkedHashSet<>();
    private Map<Character, FriendIndex> mFriendIndexs;

    private HandlerThread mBackgroundThread;
    private BackgroundHandler mBackgroundHandler;

    private KJBitmap mkjBitmap;
    private String mSearchText;
    private boolean mIsMultiSelect;
    private int mSelectUserPicSize;
    private int mTotalFriendSize;

    private Handler mUIHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            if(msg.what == MSG_DATA_PROCESS_SUCCESS){
                mLvAdapter = new FriendListAdapter();
                mLvFriends.setAdapter(mLvAdapter);
                initAlphaBar();
                mEmptyLayout.setVisibility(View.GONE);
            }else if(msg.what == MSG_SEARCH_FRIENDS_SUCCESS){
                mLvAdapter.notifyDataSetChanged();
            }else if(msg.what == MSG_SELECT_USERS_PROCESS_SUCCESS){
                SpannableStringBuilder usersPicSpannable = (SpannableStringBuilder)msg.obj;
                mTvSelectedUsers.setText(usersPicSpannable);
            }
        }
    };

    private AsyncHttpResponseHandler mFriendsListHandler =new AsyncHttpResponseHandler() {
        @Override
        public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
            FriendsList friendList = XmlUtils.toBean(FriendsList.class, responseBody);
            if(friendList == null || friendList.getFriendlist().isEmpty()){
                mEmptyLayout.setErrorType(EmptyLayout.NODATA);
            }else{
                mBackgroundHandler.sendMessage(mBackgroundHandler.obtainMessage(MSG_DATA_PROCESS,friendList));
            }
        }

        @Override
        public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {
            mEmptyLayout.setErrorType(EmptyLayout.NETWORK_ERROR);
        }
    };

    private TextWatcher mSearchTextWatcher = new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {

        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {

        }

        @Override
        public void afterTextChanged(Editable s) {
            final String searchText = s.toString();
            mSearchText = searchText;
            mBackgroundHandler.removeMessages(MSG_SEARCH_FRIENDS);
            mBackgroundHandler.sendMessageDelayed(mBackgroundHandler.obtainMessage(MSG_SEARCH_FRIENDS, searchText),200);
        }
    };

    private final Comparator<ItemModel> friendSearchComparator = new Comparator<ItemModel>() {
        @Override
        public int compare(ItemModel lhs, ItemModel rhs) {
            Friend lhsUser = (Friend) lhs.data;
            Friend rhsUser = (Friend) rhs.data;
            final String lhsUserName = lhsUser.getName();
            final String rhsUserName = rhsUser.getName();
            final String lowerCaseKeyword = mSearchText.toLowerCase();
            int result = lhsUserName.toLowerCase().indexOf(lowerCaseKeyword) - rhsUserName.toLowerCase().indexOf(lowerCaseKeyword);
            if(result == 0){
                return lhsUserName.compareTo(rhsUserName);
            }else{
                return result;
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setActionBarTitle("选择@好友");
        requestFriendsList();
        mBackgroundThread = new HandlerThread("Work Thread On SelectUserActivity");
        mBackgroundThread.start();
        mBackgroundHandler = new BackgroundHandler(mBackgroundThread.getLooper());
        mkjBitmap = new KJBitmap();
        mSelectUserPicSize = getResources().getDimensionPixelSize(R.dimen.select_user_pic_size);
    }

    @Override
    protected boolean hasBackButton() {
        return true;
    }

    @Override
    protected void initActionBar(ActionBar actionBar) {
        super.initActionBar(actionBar);
        actionBar.setDisplayOptions(actionBar.getDisplayOptions() | ActionBar.DISPLAY_SHOW_CUSTOM);
        mTvConfirm = new TextView(actionBar.getThemedContext());
        ActionBar.LayoutParams params = new ActionBar.LayoutParams( ActionBar.LayoutParams.WRAP_CONTENT, ActionBar.LayoutParams.WRAP_CONTENT,
                Gravity.END | Gravity.CENTER_VERTICAL);
        mTvConfirm.setLayoutParams(params);
        mTvConfirm.setTextColor(getResources().getColor(R.color.white));
        mTvConfirm.setOnClickListener(this);
        mTvConfirm.setVisibility(View.GONE);
        actionBar.setCustomView(mTvConfirm);
    }

    @Override
    protected int getLayoutId() {
        return R.layout.activity_select_user;
    }

    @Override
    public void initData() {

    }

    @Override
    public void initView() {
        mEmptyLayout = (EmptyLayout)findViewById(R.id.error_layout);
        mLvFriends = (ListView)findViewById(R.id.search_result_listview);
        mEtSearch = (EditText)findViewById(R.id.search_edit_text);
        mEtSearch.addTextChangedListener(mSearchTextWatcher);
        mAlphaBar = (AlphabetBar)findViewById(R.id.alphabet_bar);
        mTvAlphaTip = (TextView)findViewById(R.id.alphabet_tip);
        mTvSelectedUsers = (TextView)findViewById(R.id.selected_users_tv);
        mLvFriends.setOnScrollListener(new AbsListView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(AbsListView view, int scrollState) {
                if(scrollState == AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL){
                    hideInputMethod();
                }
            }

            @Override
            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
            }
        });
        mLvFriends.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
            @Override
            public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
                ItemModel m = mShowMdlFriends.get(position);
                if (m.type == ItemModel.TYPE_USER_INFO && !mSelectedFriends.contains(m.data) && !checkIfExceedMaxSelectCount()) {
                    Friend f = (Friend) m.data;
                    mSelectedFriends.add(f);
                    if (!mIsMultiSelect) {
                        mIsMultiSelect = true;
                        mLvAdapter.notifyDataSetChanged();
                        mTvConfirm.setVisibility(View.VISIBLE);
                        refleshSelectUsers();
                    } else {
                        mLvAdapter.refleshItemStatus(position, f);
                        refleshSelectUsers();
                    }
                }
                return true;
            }
        });
        mLvFriends.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                ItemModel m = mShowMdlFriends.get(position);
                if (m.type == ItemModel.TYPE_USER_INFO) {
                    Friend f = (Friend) m.data;
                    if (mIsMultiSelect) {
                        if (mSelectedFriends.contains(f)) {
                            mSelectedFriends.remove(f);
                        } else if(!checkIfExceedMaxSelectCount()){
                            mSelectedFriends.add(f);
                        }
                        mLvAdapter.refleshItemStatus(position, f);
                        refleshSelectUsers();
                    } else {
                        Intent resultIntent = new Intent();
                        resultIntent.putExtra(RESULT_AT_USERS, String.format("@%s ", f.getName()));
                        setResult(RESULT_OK, resultIntent);
                        finish();
                    }
                }
            }
        });

        mEmptyLayout.setOnLayoutClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                mEmptyLayout.setErrorType(EmptyLayout.NETWORK_LOADING);
                requestFriendsList();
            }
        });
    }

    private void refleshSelectUsers(){
        int selectFriendsSize = mSelectedFriends.size();
        mTvConfirm.setText(String.format("确定(%s/%s)", selectFriendsSize, mTotalFriendSize));
        if(selectFriendsSize == 0){
            mTvSelectedUsers.setVisibility(View.GONE);
        }else {
            mTvSelectedUsers.setVisibility(View.VISIBLE);
            mBackgroundHandler.sendEmptyMessage(MSG_SELECT_USERS_PROCESS);
        }
    }

    private boolean checkIfExceedMaxSelectCount(){
        boolean isExceed = mSelectedFriends.size() >= MAX_SELECT_USER_COUNT;
        if(isExceed){
            Toast.makeText(this,String.format("选择用户数不能超过%s个",MAX_SELECT_USER_COUNT),Toast.LENGTH_SHORT).show();
        }
        return isExceed;
    }

    private Bitmap getCacheUserBitmap(String url){
        if(TextUtils.isEmpty(url))
            return BitmapFactory.decodeResource(getResources(), R.drawable.widget_dface);

        Bitmap bm = mkjBitmap.getMemoryCache(url);
        if(bm == null){
            bm = BitmapFactory.decodeStream(new ByteArrayInputStream(mkjBitmap.getCache(url)));
        }
        return bm;
    }

    @Override
    public void onClick(View v) {
        StringBuilder atUsers = new StringBuilder();
        for(Friend f : mSelectedFriends){
            atUsers.append(String.format("@%s ", f.getName()));
        }
        Intent resultIntent = new Intent();
        resultIntent.putExtra(RESULT_AT_USERS,atUsers.toString());
        setResult(RESULT_OK, resultIntent);
        finish();
    }

    private void initAlphaBar(){
        mAlphaBar.setVisibility(View.VISIBLE);
        mAlphaBar.setOnAlphabetTouchListener(new AlphabetBar.OnAlphabetTouchListener() {
            @Override
            public void onTouchMove(char al) {
                FriendIndex friendIndex;
                if (al == AlphabetBar.OTHER_CHARACTOR) {
                    friendIndex = mFriendIndexs.get(OTHER_INDEX_CHAR);
                } else {
                    friendIndex = mFriendIndexs.get(al);
                }
                mTvAlphaTip.setVisibility(View.VISIBLE);
                mTvAlphaTip.setText(String.valueOf(al));
                if (friendIndex != null) {
                    mLvFriends.setSelection(friendIndex.position);
                }
            }

            @Override
            public void onTouchCancel() {
                mTvAlphaTip.setVisibility(View.GONE);
            }
        });
    }

    private void requestFriendsList(){
        AppContext appContext = (AppContext) getApplication();
        OSChinaApi.getAllFriendList(appContext.getLoginUid(), mFriendsListHandler);
    }

    private void clearHighLightTag(){
        for(ItemModel model : mShowMdlFriends){
            if(model.data instanceof Friend){
                Friend user = (Friend) model.data;
                user.setName(user.getName().replaceAll("<.+?>", ""));
            }
        }
    }

    private void hideInputMethod() {
        InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
        imm.hideSoftInputFromWindow(mEtSearch.getWindowToken(), 0);
    }

    private class ItemModel{
        static final int TYPE_CHARACTER = 0x0;
        static final int TYPE_USER_INFO = 0x1;
        int type;
        Object data;

    }

    private class FriendListAdapter extends BaseAdapter{

        Activity activity;

        SparseArray<ImageView> selectorHolder;

        FriendListAdapter(){
            this.activity = SelectUserActivity.this;
            selectorHolder = new SparseArray<>();
        }

        @Override
        public int getCount() {
            return mShowMdlFriends == null ? 0 : mShowMdlFriends.size();
        }

        @Override
        public Object getItem(int position) {
            return mShowMdlFriends.get(position);
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        @Override
        public int getItemViewType(int position) {
            return mShowMdlFriends.get(position).type;
        }

        @Override
        public int getViewTypeCount() {
            return 2;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            final int itemType = getItemViewType(position);
            final ItemModel model = mShowMdlFriends.get(position);
            if(itemType == ItemModel.TYPE_CHARACTER){
                return getAlphaTitleView(model,convertView);
            }else{
                return getItemView(position,model,convertView);
            }
        }

        private View getAlphaTitleView(final ItemModel model,View convertView){
            TextView tvletter;
            if(convertView == null){
                tvletter = (TextView) View.inflate(activity, R.layout.item_letter_index_title, null);
            }else{
                tvletter = (TextView)convertView;
            }
            Character letter = (Character)model.data;
            if(letter == OTHER_INDEX_CHAR){
                tvletter.setText("#");
            }else{
                tvletter.setText(String.valueOf(letter));
            }
            return tvletter;
        }

        private View getItemView(final int position, final ItemModel model,View convertView){
            ItemViewHolder viewHodler;
            if(convertView == null){
                convertView = View.inflate(activity,R.layout.list_select_friend,null);
                viewHodler = new ItemViewHolder();
                viewHodler.ivUserAvator = (ImageView)convertView.findViewById(R.id.iv_user_avator);
                viewHodler.tvUserName = (TextView)convertView.findViewById(R.id.tv_user_name);
                viewHodler.ivSelector = (ImageView)convertView.findViewById(R.id.iv_selector);
                convertView.setTag(viewHodler);
            }else{
                viewHodler = (ItemViewHolder)convertView.getTag();
            }

            Friend friend = (Friend)model.data;
            viewHodler.tvUserName.setText(Html.fromHtml(friend.getName()));

            selectorHolder.put(position,viewHodler.ivSelector);

            if(mIsMultiSelect){
                viewHodler.ivSelector.setVisibility(View.VISIBLE);
                if(mSelectedFriends.contains(friend)){
                    viewHodler.ivSelector.setImageResource(R.drawable.bg_cb_friend_selected);
                }else{
                    viewHodler.ivSelector.setImageResource(R.drawable.bg_cb_friend_unselect);
                }
            }else{
                viewHodler.ivSelector.setVisibility(View.GONE);
            }

            mkjBitmap.display(viewHodler.ivUserAvator,friend.getPortrait());

            return convertView;
        }

        void refleshItemStatus(int position, Friend friend){
            ImageView ivSelector = selectorHolder.get(position);
            if(ivSelector != null){
                if(mSelectedFriends.contains(friend)){
                    ivSelector.setImageResource(R.drawable.bg_cb_friend_selected);
                }else{
                    ivSelector.setImageResource(R.drawable.bg_cb_friend_unselect);
                }
            }
        }

        private class ItemViewHolder{
            ImageView ivUserAvator;
            TextView tvUserName;
            ImageView ivSelector;
        }
    }

    public class BackgroundHandler extends Handler {

        public BackgroundHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            if(msg.what == MSG_DATA_PROCESS){
                FriendsList friendList = (FriendsList)msg.obj;
                processData(friendList);
                mUIHandler.sendEmptyMessage(MSG_DATA_PROCESS_SUCCESS);
            }else if(msg.what == MSG_SEARCH_FRIENDS){
                String searchText = (String)msg.obj;
                if(mShowMdlFriends != null){
                    clearHighLightTag();
                    mShowMdlFriends.clear();
                }

                if(!TextUtils.isEmpty(searchText)){
                    searchFriends(searchText);
                }else{
                    mShowMdlFriends.addAll(mAllMdlFriends);
                }

                mUIHandler.sendEmptyMessage(MSG_SEARCH_FRIENDS_SUCCESS);
            }else if(msg.what == MSG_SELECT_USERS_PROCESS){
                SpannableStringBuilder spannable =  processSelectedUsers();
                mUIHandler.sendMessage(mUIHandler.obtainMessage(MSG_SELECT_USERS_PROCESS_SUCCESS, spannable));
            }
        }

        private void processData(FriendsList friendList){
            if(friendList != null) {

                List<Friend> allFriends = friendList.getFriendlist();
                if (allFriends == null || allFriends.isEmpty()) {
                    // no friends
                    return;
                }

                mTotalFriendSize = allFriends.size();
                mFriendIndexs = new TreeMap<>();
                Character firstAlpha;

                for (Friend f : allFriends) {
                    firstAlpha = StringUtils.getFirstLetter(f.getName().charAt(0));
                    if ('A' <= firstAlpha && firstAlpha <= 'Z') {
                        addUserIndex(firstAlpha, f);
                    } else {
                        addUserIndex(OTHER_INDEX_CHAR, f);
                    }
                }

                mShowMdlFriends = new ArrayList<>();

                ItemModel model;
                FriendIndex friendIndex;
                int itemPos = 0;
                for (java.util.Map.Entry<Character, FriendIndex> entry : mFriendIndexs.entrySet()) {
                    model = new ItemModel();
                    model.type = ItemModel.TYPE_CHARACTER;
                    model.data = entry.getKey();
                    mShowMdlFriends.add(model);
                    friendIndex = entry.getValue();
                    friendIndex.position = itemPos;
                    ++itemPos;
                    for (Friend friend : friendIndex.friends) {
                        model = new ItemModel();
                        model.type = ItemModel.TYPE_USER_INFO;
                        model.data = friend;
                        mShowMdlFriends.add(model);
                        ++itemPos;
                    }
                }

                mAllMdlFriends = new ArrayList<>();
                mAllMdlFriends.addAll(mShowMdlFriends);
            }
        }

        private void addUserIndex(char letter, Friend friend){
            FriendIndex friendIndex = mFriendIndexs.get(letter);
            if(friendIndex == null){
                friendIndex = new FriendIndex();
                mFriendIndexs.put(letter, friendIndex);
            }
            friendIndex.friends.add(friend);
        }

        private void searchFriends(String searchText){
            if(mAllMdlFriends == null || mAllMdlFriends.isEmpty())
                return;

            for(ItemModel m : mAllMdlFriends){
                if(m.type == ItemModel.TYPE_USER_INFO && m.data instanceof Friend){
                    Friend f = (Friend) m.data;
                    String name = f.getName();
                    if(name.toLowerCase().contains(searchText.toLowerCase())){
                        f.setName(name.replaceAll("((?i)" + searchText + ")",HIGHLIGHT_REPLACEMENT));
                        mShowMdlFriends.add(m);
                    }
                }
            }

            Collections.sort(mShowMdlFriends, friendSearchComparator);
        }

        private SpannableStringBuilder processSelectedUsers(){
            int selectFriendsSize = mSelectedFriends.size();

            String spanText = "";
            int picIndex;
            for(picIndex = 0 ; picIndex < selectFriendsSize ; ++picIndex){
                spanText += (picIndex + " ");
            }
            spanText = spanText.substring(0,spanText.length() - 1);
            SpannableStringBuilder spannable = new SpannableStringBuilder(spanText);

            ImageSpan imgSpan;
            Bitmap bmUser , newBmUser;
            picIndex = 0;
            int spanStart;
            String indexStr;

            for (Friend f : mSelectedFriends) {
                indexStr = String.valueOf(picIndex);
                spanStart = spanText.indexOf(indexStr);
                bmUser = getCacheUserBitmap(f.getPortrait());
                newBmUser = Bitmap.createScaledBitmap(bmUser, mSelectUserPicSize, mSelectUserPicSize, true);
                if (newBmUser == null) {
                    newBmUser = Bitmap.createScaledBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.widget_dface), mSelectUserPicSize, mSelectUserPicSize, true);
                }
                imgSpan = new ImageSpan(SelectUserActivity.this, newBmUser);
                spannable.setSpan(imgSpan, spanStart, spanStart + indexStr.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                ++picIndex;
            }

            return spannable;
        }
    }

    private class FriendIndex{
        int position;
        List<Friend> friends = new ArrayList<>();
    }
}
